<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    /* 
      每一个函数都有显示原型属性 显示原型指向原型对象
      每一个对象都有隐式原型属性
      对象的隐式原型指向构造函数的显示原型的原型对象
      原型链的终点设置为null 目的：防止原型链的循环
      this指向构造函数的实例化对象
      this是用来给实列化对象添加属性及方法
      构造函数的显示原型的属性和方法是给实例化对象使用的
      在构造函数中 如果return的是基本数据类型 则返回的是实例化对象
      如果return的是引用数据类型 贼返回的是引用数据类型
    */
    function Person(name, age) {
      this.name = name
      this.age = age
      
    }
    Person.prototype.eat = function () {
      console.log('吃东西');
    }

    //手写new 
    function myNew(Person, ...ary) {
      //1.创建一个空对象
      const obj = {}
      //2.修改构造函数的this指向 传入参数
      const re = Person.apply(obj, ary)
      console.log(re);
      //3.让对象的隐式原型指向构造函数的显示原型
      obj.__proto__ = Person.prototype
      //4.判断构造函数的返回值是引用数据类型 还是 基本数据类型
      //console.log(re);
      if (typeof re === 'object' && typeof re !== 'null' || typeof re === 'function') {
        return re
      } else {
        return obj
      }
    }
    const p1 = myNew(Person, 'li', 18) // new Person('li',18)
    console.log(p1,'p1');
    console.log(p1.__proto__ === Person.prototype);
    p1.eat()

    /* 
      new 做的四件事情
      在堆内存开辟一个新的空间
    */
  </script>
</body>

</html>